using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;


namespace Grafica1
{
    public interface IViewPortsManager
    {
    }

    public class ViewPortsManager : Microsoft.Xna.Framework.DrawableGameComponent, IViewPortsManager
    {

        Game1 myGame;
        CameraManager Cameras;
        Viewport defaultViewport;
        Viewport leftViewport;
        Viewport rightViewport;

        MyDrowableFrustum leftFrustum, rightFrustum;
        Effect fx;
        SpriteBatch spriteBatch;
        SpriteFont font;
        KeyboardState _old = new KeyboardState();
        ActionType drawingState = ActionType.ShowingHelp;

        #region Help strings
        private string leftCommands =
            "HELP SCREEN\n\n" +
            "Comandi generali\n" +
            Keys.Escape + ": ritorna al mondo\n" +
            Keys.I + ":      Mostra informazioni selle telecamere\n" +
            Keys.H + ":      Mostra questa schermata di aiuto\n" +
            "\n" +
            "Selezione telecamere\n" +
            Keys.PageUp + ":   Cambia Telecamera\n" +
            Keys.PageDown + ": Cambia Telecamera\n" +
            "\n" +
            "Movimento\n" +
            "Rotazioni\n" +
            "Up:            guarda verso il basso (pitch)\n" +
            "Down:          guarda verso l'alto (pitch)\n" +
            "Left:          ruota verso sinistra (yaw)\n" +
            "Right:         ruota verso destra (yaw)\n" +
            "LeftControl:   ruota in senso orario (roll)\n" +
            "LeftAlt:       ruota in senso antiorario (roll)\n" +
            "Spostamenti\n" +
            "W:     Muovi avanti\n" +
            "S:     Muovi indietro\n" +
            "A:     Muovi a sinistra\n" +
            "D:     Muovi a destra\n" +
            "Space: Muovi in alto\n" +
            "X:     Muovi in basso\n";

        private string rightCommand =
            "\n\n\n" +
            "Altre modifiche della telecamera\n" +
            "F1: aumenta il field of view\n" +
            "F2: diminuisce il field of view\n" +
            "N:  avvicina il near plane\n" +
            "M:  allontana il near plane\n" +
            "J:  avvicina il far plane\n" +
            "K:  allontana il far plane\n" +
            "\n" +
            "Modifiche velocita' interazione\n" +
            "RightControl:  Aumenta la velocita' di\n" +
            "               movimento della camera\n" +
            "RightShift:    Diminuisce la velocita' di\n" +
            "               movimento della camera\n" +
            "\nAlt + F4: Per uscire\n\n\n\n" +
            "Esercitazione 1\n" +
            "Steffinlongo Enrico\n" +
            "Mat: 826043\n\n" +
            "Buon divertimento";
        #endregion

        public ViewPortsManager(Game1 game)
            : base(game)
        {
            myGame = game;
            Cameras = new CameraManager(Game);
            Game.Components.Add(Cameras);
            game.Services.AddService(typeof(IViewPortsManager), this);
        }

        public override void Initialize()
        {
            leftFrustum = new MyDrowableFrustum(Color.Red, Color.Blue);
            rightFrustum = new MyDrowableFrustum(Color.Green, Color.Yellow);

            Cameras._leftViewPoint.View = Matrix.CreateLookAt(Vector3.Backward * 50 + Vector3.Up * 30, Vector3.Up * 30, Vector3.Up);
            Cameras._rightViewPoint.View = Matrix.CreateLookAt(-Vector3.Backward * 50 + Vector3.Up * 30, Vector3.Up * 30, Vector3.Up);

            Cameras.Enable = false;

            base.Initialize();
        }

        protected override void LoadContent()
        {
            defaultViewport = Game.GraphicsDevice.Viewport;
            leftViewport = defaultViewport;
            rightViewport = defaultViewport;
            leftViewport.Width = leftViewport.Width / 2 - 2;
            rightViewport.Width = rightViewport.Width / 2 - 2;
            rightViewport.X = leftViewport.Width + 4;

            Cameras._leftViewPoint.AspectRatio = leftViewport.AspectRatio;
            Cameras._rightViewPoint.AspectRatio = rightViewport.AspectRatio;

            leftFrustum.LoadContent(GraphicsDevice);
            rightFrustum.LoadContent(GraphicsDevice);

            spriteBatch = new SpriteBatch(GraphicsDevice);

            font = Game.Content.Load<SpriteFont>("SpriteFont1");

            fx = Game.Content.Load<Effect>("FrustumEffect");

            base.LoadContent();
        }

        public override void Update(GameTime gameTime)
        {
            switch (drawingState)
            {
                case ActionType.Active:
                    Game.Window.Title = "Esercitazione 1 @ " + Cameras.CurrentCamera.Name;
                    break;
                case ActionType.ShowingHelp:
                    Game.Window.Title = "Help screen";
                    break;
                case ActionType.ShowingInfos:
                    Game.Window.Title = "Cameras infos screen";
                    break;
                default:
                    break;
            }


            var state = Keyboard.GetState();

            if (state.IsKeyDown(Keys.H) && !_old.IsKeyDown(Keys.H))
            {
                switch (drawingState)
                {
                    case ActionType.Active:
                        Cameras.Enable = false;
                        drawingState = ActionType.ShowingHelp;
                        break;
                    case ActionType.ShowingInfos:
                        drawingState = ActionType.ShowingHelp;
                        break;
                    case ActionType.ShowingHelp:
                        drawingState = ActionType.Active;
                        Cameras.Enable = true;
                        break;
                    default:
                        break;
                }
            }

            if (state.IsKeyDown(Keys.I) && !_old.IsKeyDown(Keys.I))
            {
                switch (drawingState)
                {
                    case ActionType.Active:
                        Cameras.Enable = false;
                        drawingState = ActionType.ShowingInfos;
                        break;
                    case ActionType.ShowingHelp:
                        drawingState = ActionType.ShowingInfos;
                        break;
                    case ActionType.ShowingInfos:
                        drawingState = ActionType.Active;
                        Cameras.Enable = true;
                        break;
                    default:
                        break;
                }
            }


            if (state.IsKeyDown(Keys.Escape) && !_old.IsKeyDown(Keys.Escape))
            {
                Cameras.Enable = true;
                drawingState = ActionType.Active;
            }


            _old = state;
            base.Update(gameTime);
        }


        public override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Viewport = defaultViewport;

            if (drawingState == ActionType.ShowingHelp)
            {
                ShowingHelp();
            }
            else
            {
                DrawSplitted();
            }

            base.Draw(gameTime);
        }

        private void ShowingHelp()
        {
            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone);
            spriteBatch.Draw(myGame.separator, new Vector2(leftViewport.Width, 0), Color.White);
            spriteBatch.DrawString(font, leftCommands, new Vector2(2, 0), Color.Black);
            spriteBatch.DrawString(font, rightCommand, new Vector2(defaultViewport.Width / 2 + 4, 0), Color.Black);

            spriteBatch.End();
        }

        private void DrawSplitted()
        {

            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone);
            spriteBatch.Draw(myGame.separator, new Vector2(leftViewport.Width, 0), Color.White);
            spriteBatch.End();

            Game.GraphicsDevice.Viewport = leftViewport;

            if (Cameras.Enable)
            {

                foreach (var mesh in myGame.model.Meshes)
                {
                    foreach (var efx in mesh.Effects)
                    {
                        efx.Parameters["World"].SetValue(Matrix.Identity);
                        efx.Parameters["View"].SetValue(Cameras._leftViewPoint.View);
                        efx.Parameters["Projection"].SetValue(Cameras._leftViewPoint.Projection);
                        efx.Parameters["LightPosition"].SetValue(new Vector4(200, 200, 200, 1));
                        efx.Parameters["EyePosition"].SetValue(Cameras._leftViewPoint.position);
                        efx.Parameters["SpecularColor"].SetValue(Color.White.ToVector4());
                    }

                    mesh.Draw();

                }

                myGame.cubo.Draw(Matrix.Identity, Cameras._leftViewPoint.View, Cameras._leftViewPoint.Projection);
                myGame.camera.Draw(Matrix.CreateFromQuaternion(Cameras._rightViewPoint.orientation) * Matrix.CreateTranslation(Cameras._rightViewPoint.position), Cameras._leftViewPoint.View, Cameras._leftViewPoint.Projection);

                rightFrustum.Draw(GraphicsDevice, fx, Matrix.Invert(Cameras._rightViewPoint.Projection) * Matrix.Invert(Cameras._rightViewPoint.View),
                    Cameras._leftViewPoint.View,
                    Cameras._leftViewPoint.Projection);

                var lookTo = Matrix.CreateFromQuaternion(Cameras._leftViewPoint.orientation) * Matrix.CreateTranslation(Cameras._leftViewPoint.position);
                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearWrap, DepthStencilState.Default, RasterizerState.CullNone);
                spriteBatch.DrawString(font, "in: " + Cameras._leftViewPoint.position, new Vector2(2, 0), Color.Black);
                spriteBatch.DrawString(font, "looking to: " + lookTo.Forward, new Vector2(2, 15), Color.Black);
                spriteBatch.DrawString(font, "up: " + lookTo.Up, new Vector2(2, 30), Color.Black);
                spriteBatch.End();
            }
            else
            {
                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearWrap, DepthStencilState.Default, RasterizerState.CullNone);
                spriteBatch.DrawString(font, Cameras._leftViewPoint.ToString(), new Vector2(2, 0), Color.Black);
                spriteBatch.End();

            }

            Game.GraphicsDevice.Viewport = rightViewport;

            if (Cameras.Enable)
            {
                foreach (var mesh in myGame.model.Meshes)
                {
                    foreach (var efx in mesh.Effects)
                    {
                        efx.Parameters["World"].SetValue(Matrix.Identity);
                        efx.Parameters["View"].SetValue(Cameras._rightViewPoint.View);
                        efx.Parameters["Projection"].SetValue(Cameras._rightViewPoint.Projection);
                        efx.Parameters["LightPosition"].SetValue(new Vector4(200, 200, 200, 1));
                        efx.Parameters["EyePosition"].SetValue(Cameras._rightViewPoint.position);
                        efx.Parameters["SpecularColor"].SetValue(Color.White.ToVector4());
                    }

                    mesh.Draw();
                }

                myGame.cubo.Draw(Matrix.Identity, Cameras._rightViewPoint.View, Cameras._rightViewPoint.Projection);
                myGame.camera.Draw(Matrix.CreateFromQuaternion(Cameras._leftViewPoint.orientation) * Matrix.CreateTranslation(Cameras._leftViewPoint.position), Cameras._rightViewPoint.View, Cameras._rightViewPoint.Projection);


                leftFrustum.Draw(GraphicsDevice, fx, Matrix.Invert(Cameras._leftViewPoint.Projection) * Matrix.Invert(Cameras._leftViewPoint.View),
                    Cameras._rightViewPoint.View,
                    Cameras._rightViewPoint.Projection);

                var lookTo = Matrix.CreateFromQuaternion(Cameras._rightViewPoint.orientation) * Matrix.CreateTranslation(Cameras._rightViewPoint.position);
                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone);
                spriteBatch.DrawString(font, "in: " + Cameras._rightViewPoint.position, new Vector2(2, 0), Color.Black);
                spriteBatch.DrawString(font, "looking to: " + lookTo.Forward, new Vector2(2, 15), Color.Black);
                spriteBatch.DrawString(font, "up: " + lookTo.Up, new Vector2(2, 30), Color.Black);
                spriteBatch.End();

            }

            else
            {
                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearWrap, DepthStencilState.Default, RasterizerState.CullNone);
                spriteBatch.DrawString(font, Cameras._rightViewPoint.ToString(), new Vector2(2, 0), Color.Black);
                spriteBatch.End();

            }
        }

        enum ActionType
        {
            Active,
            ShowingHelp,
            ShowingInfos
        }
    }
}
